package com.sunye.mongodb.service.impl;


import cn.hutool.core.convert.Convert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.sunye.elasticsearch.entity.EsDogSearchDTO;
import com.sunye.mongodb.MongoDbPageable;
import com.sunye.mongodb.MongoDogIndex;
import com.sunye.mongodb.SearchResponse;
import com.sunye.mongodb.service.MongoDogIndexService;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 商品索引业务层实现
 *
 * @author paulG
 * @since 2020/10/14
 **/
@Service
public class MongoDogIndexServiceImpl implements MongoDogIndexService {

    @Autowired
    private MongoTemplate mongoTemplate;

    //参考https://blog.csdn.net/m0_49194578/article/details/125410495
    //参考https://blog.csdn.net/weixin_44316527/article/details/121093331
    //MongoDB 其中同一字段出现两次，条件查询出错
    //只能有一个andCriterias和orOperator方法

    /**
         SELECT * FROM es_dog WHERE recommend = 1
         AND (
             dogName LIKE '%花花%'
             OR introduct LIKE '%花花%'
             OR sellingPointList LIKE '%花花%'
         )
         AND (skuList.id = 1 OR skuList.id = 2)
     */
    @Override
    public SearchResponse searchDogsByMongoDB(EsDogSearchDTO dogSearchDTO,Integer start,Integer size) {
        Criteria criteria = new Criteria();
        List<Criteria> orCriterias = new ArrayList<>();
        if(StringUtils.isNotBlank(dogSearchDTO.getKeyword()) && dogSearchDTO.getSkuIds() != null && !dogSearchDTO.getSkuIds().isEmpty()){
            //sku-->嵌套查询(or的查询)
            for (String skuId : dogSearchDTO.getSkuIds()) {
                orCriterias.add(Criteria.where("skuList.id").is(skuId));
            }
            criteria.orOperator(
                    Criteria.where("dogName").regex(".*?\\" +dogSearchDTO.getKeyword()+ ".*"),
                    Criteria.where("introduct").regex(".*?\\" +dogSearchDTO.getKeyword()+ ".*"),
                    Criteria.where("sellingPointList.advantage").regex(".*?\\" +dogSearchDTO.getKeyword()+ ".*").
                            orOperator(
                                    orCriterias.toArray(new Criteria[0])
                            ));
        }else if(StringUtils.isNotBlank(dogSearchDTO.getKeyword())){
            criteria.orOperator(
                    Criteria.where("dogName").regex(".*?\\" +dogSearchDTO.getKeyword()+ ".*"),
                    Criteria.where("introduct").regex(".*?\\" +dogSearchDTO.getKeyword()+ ".*"),
                    Criteria.where("sellingPointList.advantage").regex(".*?\\" +dogSearchDTO.getKeyword()+ ".*"));
        }else if(dogSearchDTO.getSkuIds() != null && !dogSearchDTO.getSkuIds().isEmpty()){
            //sku-->嵌套查询(or的查询)
            for (String skuId : dogSearchDTO.getSkuIds()) {
                orCriterias.add(Criteria.where("skuList.id").is(skuId));
            }
            criteria.orOperator(orCriterias.toArray(new Criteria[0]));
        }
        //颜色
        if (StringUtils.isNotBlank(dogSearchDTO.getColor())) {
            criteria.and("color").regex(".*?\\" +dogSearchDTO.getColor()+ ".*");
        }

        //是否为推荐狗
        if (dogSearchDTO.getRecommend() != null) {
            criteria.and("recommend").is(dogSearchDTO.getRecommend());
        }

        //价格区间判定
        if (StringUtils.isNotEmpty(dogSearchDTO.getPrice())) {
            String[] prices = dogSearchDTO.getPrice().split("_");
            double min = Convert.toDouble(prices[0], 0.0);
            double max = Integer.MAX_VALUE;

            if (prices.length == 2) {
                max = Convert.toDouble(prices[1], Double.MAX_VALUE);
            }
            criteria.and("price").gte(min).lte(max);
        }
        //未上架的商品不显示
        criteria.and("saleStatus").is("1");

        //卖点-->嵌套查询 (and的查询)
        if (dogSearchDTO.getSellingPointIds() != null && !dogSearchDTO.getSellingPointIds().isEmpty()) {
            List<Criteria> andCriterias = new ArrayList<>();
            for (String pointId : dogSearchDTO.getSellingPointIds()) {
                andCriterias.add(Criteria.where("sellingPointList.sellingPointId").is(pointId));
            }
            criteria.andOperator(andCriterias.toArray(new Criteria[0]));
        }
        Sort sort = null;
        if (StringUtils.isNotBlank(dogSearchDTO.getPosition())) {
            //参考https://blog.csdn.net/w1316022737/article/details/96115156
            String[] split = dogSearchDTO.getPosition().split("_");
            Double lat = Double.parseDouble(split[0]);
            Double lon = Double.parseDouble(split[1]);
            //按照距离近的排序
            Point point = new Point(lon,lat);
            Query query = new Query(criteria);
            System.out.println("query = " + query);
            NearQuery nearQuery = NearQuery.near(point, Metrics.KILOMETERS).query(query);
            System.out.println("nearQuery = " + nearQuery);
            //分页
            Pageable pageable = PageRequest.of(start-1, size);
            //查询总数量
            Long total = mongoTemplate.count(query, MongoDogIndex.class);
            List<GeoResult<MongoDogIndex>> contentList = mongoTemplate.geoNear(nearQuery.with(pageable), MongoDogIndex.class).getContent();
            List<MongoDogIndex> sceneryResultList = contentList.stream().map(item -> item.getContent()).collect(Collectors.toList());
            SearchResponse res = new SearchResponse();
            res.setMongoDogIndexList(sceneryResultList);
            res.setPageNo(start);
            res.setPageSize(size);
            res.setTotal(total);
            res.setTotalPages((res.getTotal() + res.getPageSize() - 1) / res.getPageSize());
            return res;
        }else if(StringUtils.isNotBlank(dogSearchDTO.getSort())){
            //排序字段排序（价格和年龄）
            String[] fileds = dogSearchDTO.getSort().split(",");
            for (String filed : fileds) {
                String[] sorts = filed.split("_");
                sort = Sort.by("asc".equals(sorts[1]) ? Sort.Direction.ASC:Sort.Direction.DESC,sorts[0]);
            }
        }else{
            //默认按照销量排序
            sort = Sort.by(Sort.Direction.DESC,"salesNumber");
        }
        Query query = new Query(criteria);
        System.out.println("query = " + query);
        //分页
        Pageable pageable = PageRequest.of(start-1, size, sort);
        //查询总数量
        Long total = mongoTemplate.count(query, MongoDogIndex.class);
        //查询
        List<MongoDogIndex> prs = mongoTemplate.find(query.with(pageable), MongoDogIndex.class);
        SearchResponse res = new SearchResponse();
        res.setMongoDogIndexList(prs);
        res.setPageNo(start);
        res.setPageSize(size);
        res.setTotal(total);
        res.setTotalPages((res.getTotal() + res.getPageSize() - 1) / res.getPageSize());
        return res;
    }

    @Override
    public List searchMongDbGroupBy(EsDogSearchDTO dogSearchDTO) {

        //select age, count(*) as ageCount from es_dog WHERE sale_status = '1' AND deleted = '0' group by age; -- age是int不用写keyword
        String[] field = {"age"}; 		//分组的依据，根据那些参数进行分组
        Criteria criteria = new Criteria();
        criteria.and("saleStatus").is("1");
        criteria.and("deleted").is("0");
        Aggregation aggregation1 = Aggregation.newAggregation(
                Aggregation.match(criteria),	//条件筛选    可以跟好几个条件
                Aggregation.group(field).count().as("sum"),		//分组统计收藏量    ，as 起别名
                Aggregation.sort(Sort.Direction.DESC, "sum")	//按照收藏量倒叙排序
        );
        //构建查询条件		//这是我自己需要拿出来的数据，放到集合中
        List<Map> params = new ArrayList<>();
        //执行
        AggregationResults<BasicDBObject> outputTypeCount1 = mongoTemplate.aggregate(aggregation1, MongoDogIndex.class, BasicDBObject.class);
        //迭代器进行迭代
        for (Iterator<BasicDBObject> iterator = outputTypeCount1.iterator(); iterator.hasNext(); ) {
            DBObject obj = iterator.next();
            Map map = new HashMap();
            String age = obj.get("_id").toString();
            map.put("age",age);
            String sum = obj.get("sum").toString();
            map.put("sum",sum);
            params.add(map);
        }

        return params;
    }
}

